package com.tools.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author LY
 * @Description 日期工具类
 */
public class DateUtil {

    private static Logger logger = LoggerFactory.getLogger(DateUtil.class);

    public static final String C_DATA_PATTON_YYYYMM = "yyyyMM";

    public static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 将Date类型的日期转换为系统参数定义的格式的字符串。
     * @param aTs_Datetime
     * @param as_Pattern
     * @return
     */
    public static String format(Date aTs_Datetime, String as_Pattern) {
        if (aTs_Datetime == null || as_Pattern == null) {
            return null;
        }
        SimpleDateFormat dateFromat = new SimpleDateFormat();
        dateFromat.applyPattern(as_Pattern);

        return dateFromat.format(aTs_Datetime);
    }

    /**
     * 取得当前日期N天前的日期
     *
     * @param days
     * @return
     */
    public static Date dynamicDays(String days) {
        Date retDate = null;
        try {
            Calendar cal = Calendar.getInstance();
            int date_int = (Integer.parseInt(days));
            if (date_int <= 0) {
                return retDate;
            }
            date_int = (date_int * -1) + 1;
            cal.add(Calendar.DAY_OF_YEAR, date_int);
            retDate = simpleDateFormat.parse(simpleDateFormat.format(cal.getTime()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return retDate;
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int daysBetween(Date date1, Date date2) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(date2);
        long time2 = cal.getTimeInMillis();
        long between_days = (time2 - time1) / (1000 * 3600 * 24);

        return Integer.parseInt(String.valueOf(between_days));
    }

    /**
     * 计算两个日期之间相差的时间戳
     *
     * @param date1
     * @param date2
     * @return
     */
    public static long timeInMillisBetween(Date date1, Date date2) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(date2);
        long time2 = cal.getTimeInMillis();
        long between_days = time2 - time1;
        return between_days;
    }

    /**
     * 获取今天23点59分59秒
     */
    public static Date getEndToDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        Date date = calendar.getTime();
        logger.error(date + "");
        return date;
    }

    /**
     * 获得当前系统n月前/后的日期
     * @param Nmonth >0系统n月后的日期，<0系统n月前的日期
     * @return
     */
    public static String lastNMonth(int Nmonth) {
        Date date = new Date();// 当前日期
        Calendar calendar = Calendar.getInstance();// 日历对象
        calendar.setTime(date);// 设置当前日期
        calendar.add(Calendar.MONTH, Nmonth);// 月份减一
        return simpleDateFormat.format(calendar.getTime());
    }

    /**
     * 获得当月的第一天, 如2009-10-01 00:00:00
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfMonth(Date date) {
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTime(date);
        gc.set(Calendar.DAY_OF_MONTH,
                gc.getActualMinimum(Calendar.DAY_OF_MONTH));
        gc.set(Calendar.HOUR_OF_DAY, gc.getActualMinimum(Calendar.HOUR_OF_DAY));
        gc.set(Calendar.MINUTE, gc.getActualMinimum(Calendar.MINUTE));
        gc.set(Calendar.SECOND, gc.getActualMinimum(Calendar.SECOND));
        return gc.getTime();
    }

    /**
     * 获得当月的最后一天, 如2009-10-30 23:59:59
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfMonth(Date date) {
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTime(date);
        gc.set(Calendar.DAY_OF_MONTH,
                gc.getActualMaximum(Calendar.DAY_OF_MONTH));
        gc.set(Calendar.HOUR_OF_DAY, gc.getActualMaximum(Calendar.HOUR_OF_DAY));
        gc.set(Calendar.MINUTE, gc.getActualMaximum(Calendar.MINUTE));
        gc.set(Calendar.SECOND, gc.getActualMaximum(Calendar.SECOND));
        return gc.getTime();
    }

    /**
     * 获取某周第一天日期 00点:00分:00秒
     *
     * @param date  这周中的一天
     * @param start 1--第一天是周日， 2--第一天是周一， 类推
     * @return
     */
    public static Date getFirstDayOfWeek(Date date, int start) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        int day_of_week = cal.get(Calendar.DAY_OF_WEEK) - start;
        cal.add(Calendar.DATE, -day_of_week);

        cal.set(Calendar.HOUR_OF_DAY,
                cal.getActualMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getActualMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getActualMinimum(Calendar.SECOND));
        return cal.getTime();
    }

    /**
     * 获取某周最后一天日期 23:59:59
     *
     * @param date  这周中的一天
     * @param start start 1--第一天是周日， 2--第一天是周一， 类推
     * @return
     */
    public static Date getLastDayOfWeek(Date date, int start) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        int day_of_week = cal.get(Calendar.DAY_OF_WEEK) - start;
        cal.add(Calendar.DATE, -day_of_week); // 获得第一天
        cal.add(Calendar.DATE, 6); // +6天 就得到最后一天

        cal.set(Calendar.HOUR_OF_DAY,
                cal.getActualMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getActualMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getActualMaximum(Calendar.SECOND));
        return cal.getTime();
    }

    /**
     * 获得上月第一天的日期
     * @return
     */
    public static String getPreviousMonthFirst() {
        String str = "";
        Calendar lastDate = Calendar.getInstance();
        lastDate.add(Calendar.MONTH, -1);// 减一个月
        lastDate.set(Calendar.DATE, 1);// 设为当前月的1号
        str = simpleDateFormat.format(lastDate.getTime());
        return str;
    }

    /**
     * 获得上月最后一天的日期
     * @return
     */
    public static String getPreviousMonthEnd() {
        String str = "";
        Calendar lastDate = Calendar.getInstance();
        lastDate.add(Calendar.MONTH, -1);// 减一个月
        lastDate.set(Calendar.DATE, 1);// 把日期设置为当月第一天
        lastDate.roll(Calendar.DATE, -1);// 日期回滚一天，也就是本月最后一天
        str = simpleDateFormat.format(lastDate.getTime());
        return str;
    }

    /**
     * 获得下个月第一天的日期
     * @return
     */
    public static String getNextMonthFirst() {
        String str = "";
        Calendar lastDate = Calendar.getInstance();
        lastDate.add(Calendar.MONTH, 1);// 加一个月
        lastDate.set(Calendar.DATE, 1);// 把日期设置为当月第一天
        str = simpleDateFormat.format(lastDate.getTime());
        return str;
    }

    /**
     * 获得下个月最后一天的日期
     * @return
     */
    public static String getNextMonthEnd() {
        String str = "";
        Calendar lastDate = Calendar.getInstance();
        lastDate.add(Calendar.MONTH, 1);// 加一个月
        lastDate.set(Calendar.DATE, 1);// 把日期设置为当月第一天
        lastDate.roll(Calendar.DATE, -1);// 日期回滚一天，也就是本月最后一天
        str = simpleDateFormat.format(lastDate.getTime());
        return str;
    }

    /**
     * 获取某个日期mins分钟后的日期
     *
     * @param date
     * @param mins
     * @return
     */
    public static Date getAfterNMinute(Date date, int mins) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.add(Calendar.MINUTE, mins);
        return cal.getTime();

    }

    /**
     * 判断两个日期是否相等，转成字符串后进行比较
     * @param d1
     * @param d2
     * @param dateType 时间格式类型
     * @return
     */
    public static Boolean compareDate(Date d1, Date d2, String dateType) {
        SimpleDateFormat sdf = new SimpleDateFormat(dateType);
        String s1 = sdf.format(d1);
        String s2 = sdf.format(d2);
        return s1.equals(s2);
    }

    /**
     * 判断date是否在d1与d2之间
     *
     * @param date
     * @param d1
     * @param d2
     * @return
     */
    public static Boolean DateIfBetweenDates(Date date, Date d1, Date d2) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        long dateTime = cal.getTimeInMillis();
        cal.setTime(d1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(d2);
        long time2 = cal.getTimeInMillis();

        long start = dateTime - time1;
        long end = dateTime - time2;
        return (start >= 0 && end <= 0);
    }

    /**
     * 取日期的相差n月的第一天
     * @param now
     * @param n
     * @return
     */
    public static Date getPreviousMonth(Date now, int n) {
        Calendar lastDate = Calendar.getInstance();
        lastDate.setTime(now);
        lastDate.add(Calendar.MONTH, n);// 减一个月
        lastDate.set(Calendar.DATE, 1);
        return lastDate.getTime();
    }

    /**
     * 取日期的相差n周的第一天
     * @param now
     * @param n
     * @return
     */
    public static Date getFirstDayOfWeekMonth(Date now, int n) {
        Calendar lastDate = Calendar.getInstance();
        lastDate.setTime(now);
        lastDate.add(Calendar.WEEK_OF_MONTH, n);// 减一个月
        lastDate.set(Calendar.DAY_OF_WEEK, 2);
        return lastDate.getTime();
    }

    /**
     * 按当前时间生成指定格式日期
     * @param dateFormat 日期格式
     * @return
     */
    public static String getCurrentDate(String dateFormat) {
        return new SimpleDateFormat(dateFormat).format(new Date());
    }

    /**
     * 按日加减日期
     *
     * @param date ：日期
     * @param num  ：要加减的日数
     * @return：成功，则返回加减后的日期；失败，则返回null
     */
    public static Date addDays(Date date, int num) {
        if (date == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(5, num);

        return c.getTime();
    }

    /**
     * 当前日期的前一天
     */
    public static Date getNextDay() {
        Calendar calendar = Calendar.getInstance();//此时打印它获取的是系统当前时间
        calendar.add(Calendar.DATE, -1);    //得到前一天
        Date yestedayDate = calendar.getTime();
        return yestedayDate;
    }

    /**
     * 获取指定日期的指定天的时间
     *
     * @param date
     * @param d
     * @return
     */
    public static Date getDayByDate(Date date, int d) {
        if (date == null) {
            return null;
        }

        String year = format(date, "yyyy");
        String month = format(date, "MM");

        GregorianCalendar calendar = new GregorianCalendar(
                Integer.parseInt(year), Integer.parseInt(month) - 1,
                d);

        return calendar.getTime();
    }

    /**
     * 获取指定日期的N月的日期
     *
     * @param date
     * @param n
     * @return
     */
    public static Date getMonthDateByDate(Date date, int n) {
        if (date == null) {
            return null;
        }

        String year = format(date, "yyyy");
        String month = format(date, "MM");
        String day = format(date, "MM");
        String hh = format(date, "HH");
        String mm = format(date, "mm");
        String ss = format(date, "ss");

        GregorianCalendar calendar = new GregorianCalendar(
                Integer.parseInt(year), Integer.parseInt(month) - 1,
                Integer.parseInt(day), Integer.parseInt(hh), Integer.parseInt(mm), Integer.parseInt(ss));
        calendar.add(Calendar.MONTH, n);
        return calendar.getTime();
    }

    /**
     * 本月第一天
     *
     * @return
     */
    public static String getThisMonthFirst() {
        Calendar lastDate = Calendar.getInstance();
        // 设为当前月的1号
        lastDate.set(Calendar.DATE, 1);
        return simpleDateFormat.format(lastDate.getTime());
    }

    /**
     * 本月最后一天
     *
     * @return
     */
    public static String getThisMonthEnd() {
        Calendar lastDate = Calendar.getInstance();
        // 把日期设置为当月第一天
        lastDate.set(Calendar.DATE, 1);
        // 日期回滚一天，也就是本月最后一天
        lastDate.roll(Calendar.DATE, -1);
        return simpleDateFormat.format(lastDate.getTime());
    }

    /**
     * 间隔10分钟
     * @param lastDate 指定时间+10分钟
     * @param nowDate 指定时间
     * @return
     */
    public static boolean moreThan10Min(Date lastDate, Date nowDate) {
        Calendar c = Calendar.getInstance();
        c.setTime(lastDate);
        //加十分钟
        c.add(Calendar.MINUTE, 10);
        Date tenMinLaterTime = c.getTime();
        return nowDate.getTime() >= tenMinLaterTime.getTime();
    }

    /**
     * 获取两个日期的月数
     */
    public static int getMonthDiff(Date smallDate,Date largeDate){
        Calendar c1=Calendar.getInstance();
        Calendar c2=Calendar.getInstance();
        c1.setTime(largeDate);
        c2.setTime(smallDate);
        int year1=c1.get(Calendar.YEAR);
        int year2=c2.get(Calendar.YEAR);
        int month1=c1.get(Calendar.MONTH);
        int month2=c2.get(Calendar.MONTH);
        // 获取年的差值
        int yearInterval=year1-year2;
        // 获取月数差值
        int monthInterval=month1-month2;
        int monthsDiff=yearInterval*12+monthInterval;
        return monthsDiff;
    }

    /**
     * 获取指定日期的间隔n月的第一天日期
     * @param strFormat
     * @param currMonth
     * @param n 正数，下n月；负数，上n月
     * @return
     */
    public static String getIntervalMonthFirstDay(String strFormat,String currMonth,int n) {
        SimpleDateFormat format = new SimpleDateFormat(strFormat);

        Date date = new Date();
        try{
            date = format.parse(currMonth);
        }catch(Exception e){
            e.printStackTrace();
        }
        String str = "";
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DATE, 1);// 设为目标月的1号
        c.add(Calendar.MONTH, n);// n 正数，下n月；0 本月，负数，上n月

        return simpleDateFormat.format(c.getTime());
    }

    /**
     * 获取两个日期之间的所有月份，输入输出格式：yyyyMM
     * @param minDate 开始日期
     * @param maxDate 结束日期
     * @return
     */
    public static List<String> getMonthBetween(String minDate, String maxDate) {
        List<String> result = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtil.C_DATA_PATTON_YYYYMM);//格式化为年月

        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();
        try{
            min.setTime(sdf.parse(minDate));
            min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);

            max.setTime(sdf.parse(maxDate));
            max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
            Calendar curr = min;
            while (curr.before(max)) {
                result.add(sdf.format(curr.getTime()));
                curr.add(Calendar.MONTH, 1);
            }
        }catch(Exception e){
            e.printStackTrace();
            return null;
        }
        return result;
    }

    /**
     * 日期按指定格式转字符串
     * @param strFormat 格式
     * @param date 日期
     * @return
     */
    public static String dateToStr(String strFormat,Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat(strFormat);
        String str = sdf.format(date);
        return str;
    }

    public static void main(String[] args) {
        System.out.println(getLastDayOfWeek(new Date(), 1));
    }

}